﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Media.Imaging;
using SilverlightPlayground.RFB.Silverlight.Dialogs;
using SilverlightPlayground.RFB.Security;

namespace SilverlightPlayground.RFB.Silverlight
{
    public partial class MainPage : UserControl
    {
        /// <summary>
        /// Gets or sets the bit map.
        /// </summary>
        /// <value>The bit map.</value>
        private WriteableBitmap BitMap { get; set; }
        /// <summary>
        /// Gets or sets the client.
        /// </summary>
        /// <value>The client.</value>
        public RfbClient Client { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="MainPage"/> class.
        /// </summary>
        public MainPage()
        {
            InitializeComponent();
            this.Loaded += new RoutedEventHandler(MainPage_Loaded);
            this.MouseRightButtonUp += (s, e) => e.Handled = true;
            this.MouseEnter += (s, e) => this.EvaluateMouse(e);
            this.MouseMove += (s, e) => this.EvaluateMouse(e);
            this.bDisconnect.Click += (s, e) => this.Disconnect();
            VisualStateManager.GoToState(this, "Closed", true);
        }

        /// <summary>
        /// Evaluates the mouse.
        /// </summary>
        /// <param name="e">The <see cref="System.Windows.Input.MouseEventArgs"/> instance containing the event data.</param>
        private void EvaluateMouse(MouseEventArgs e)
        {
            Point point = e.GetPosition(this.LayoutRoot);

            if (point.Y < 100)
                VisualStateManager.GoToState(this, "Open", true);
            else
                VisualStateManager.GoToState(this, "Closed", true);
        }

        /// <summary>
        /// Handles the Loaded event of the MainPage control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            this.ShowConnect();
        }

        /// <summary>
        /// Shows the connect.
        /// </summary>
        private void ShowConnect()
        {
            this.Connect("localhost", 4531);

            //ConnectionWindow window = new ConnectionWindow();
            //window.Closed += (s, args) => this.Connect(window.Host, window.Port, window.Password);
            //window.Show();
        }

        /// <summary>
        /// Connects the specified host.
        /// </summary>
        /// <param name="host">The host.</param>
        /// <param name="port">The port.</param>
        /// <param name="password">The password.</param>
        private void Connect(string host, int port)
        {
            this.Client = new RfbClient(host, port);
            this.Client.ServerScaling = RfbServerScaling.None;
            this.Client.ShareServer = true;
            this.Client.PixelSize = RfbPixelSize.Unspec;
            this.Client.FrameBufferUpdate += new EventHandler<FrameBufferUpdateEventArgs>(Client_FrameBufferUpdate);
            this.Client.Failure += new EventHandler<RfbFailureEventArgs>(Client_Failure);
            this.Client.ResizeFrameBuffer += new EventHandler(Client_ResizeFrameBuffer);
            this.Client.RequestCredentials += new EventHandler<Security.RfbRequestCredentialsEventArgs>(Client_RequestCredentials);
            this.BitMap = new WriteableBitmap(1, 1);
            this.vnc.Source = this.BitMap;
            this.Client.Connect();
        }

        void Client_RequestCredentials(object sender, Security.RfbRequestCredentialsEventArgs e)
        {
            RfbVNCChallengeSecurityToken token = e.SecurityToken as RfbVNCChallengeSecurityToken;

            if (token != null)
            {
                token.Password = "selecta";
                this.Client.Login(token);
            }
        }

        private void Disconnect()
        {
            this.Client.Close();
            this.BitMap = new WriteableBitmap(1, 1);
            this.vnc.Source = this.BitMap;
            this.ShowConnect();
            VisualStateManager.GoToState(this, "Closed", true);
        }

        /// <summary>
        /// Handles the ResizeFrameBuffer event of the Client control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        void Client_ResizeFrameBuffer(object sender, EventArgs e)
        {
            this.MakeWindowProportional(this.Client.Server.Width, this.Client.Server.Height);
            this.BitMap = new WriteableBitmap(this.Client.Server.Width, this.Client.Server.Height);
            this.vnc.Source = this.BitMap;
        }

        /// <summary>
        /// Makes the window proportional.
        /// </summary>
        /// <param name="width">The width.</param>
        /// <param name="height">The height.</param>
        private void MakeWindowProportional(double width, double height)
        {
            double proportion = width / height;
            Application.Current.MainWindow.Height = Application.Current.MainWindow.Width / proportion;
            Application.Current.MainWindow.Activate();
        }

        /// <summary>
        /// Handles the Failure event of the Client control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="SilverlightPlayground.RFB.RfbFailureEventArgs"/> instance containing the event data.</param>
        void Client_Failure(object sender, RfbFailureEventArgs e)
        {
            ErrorWindow window = new ErrorWindow();
            window.Message = e.Error.ToString();
            window.Closed += (s, args) => this.ShowConnect();
            window.Show();
        }

        /// <summary>
        /// Handles the FrameBufferUpdate event of the Client control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="SilverlightPlayground.RFB.FrameBufferUpdateEventArgs"/> instance containing the event data.</param>
        void Client_FrameBufferUpdate(object sender, FrameBufferUpdateEventArgs e)
        {
            lock (this.BitMap)
            {
                this.BitMap.Blit(e.Rectangle, e.Frame, new Rect(0, 0, e.Rectangle.Width, e.Rectangle.Height), WriteableBitmapExtensions.BlendMode.None);
                this.BitMap.Invalidate();
            }
        }
    }
}
